#include "PDA.h"
#include "ReadFile.h"

Stack x[9];

int FindTop (char c) {
    int i = 0;
    boolean found = false;
    while ((i < 9) && (!found)) {
        if (IsEmpty(x[i])) {
            i++;
        } else if (InfoTop(x[i]) == c) {
            found = true;
        } else {
            i++;
        }
    }
    return i;
}

int FindEmpty() {
    int i = 0;
    boolean found = false;
    while ((i < 9) && (!found)) {
        if (IsEmpty(x[i])) {
            found = true;
        } else {
            i++;
        }
    }
    return i;
}

boolean IsInArray (char c) {
    boolean found = false;
    int i = 0;
    while (i < 9) {
        if (!IsEmpty(x[i])) {
            if (InfoTop(x[i]) == c) {
                found = true;
                i++;
            } else {
                i++;
            }
        } else {
            i++;
        }
    }
    return found;
}

boolean isEmptyArray () {
    boolean found;
    if (IsEmpty(x[0])) {
        found = true;
    } else {
        found = false;
    }
    return found;
}

void FixArray () {
    char c;
    int i = 0;
    int j;
    int temp;
    Stack dummy;
    CreateEmpty(&dummy);
    
    while (i < 9) {
        if (!IsEmpty(x[i])) {
            i++;
        } else {
            j = i+1;
            while (j < 9) {
                if (!IsEmpty(x[j])) {
                    while(!IsEmpty(x[j])) {
                        Pop(&x[j],&c);
                        Push(&dummy,c);
                    }
                    while(!IsEmpty(dummy)) {
                        Pop(&dummy,&c);
                        Push(&x[i],c);
                    }
                }
                j++;
            }
            i++;
        }
    }
}

boolean IsNonTerminal () {
    int i = 0;
    boolean found = false;

    while ((i < 9) && (!found)) {
        if (!IsEmpty(x[i])) {
            if ((InfoTop(x[i]) >= 'A') && (InfoTop(x[i]) <= 'Z')) {
                found = true;
            } else {
                i++;
            }
        } else {
            i++;
        }
    }
    return found;
}

boolean IsTerminal () {
    int i = 0;
    boolean found = true;

    while ((i < 9) && (found)) {
        if (!IsEmpty(x[i])) {
            if ((InfoTop(x[i]) >= 'A') && (InfoTop(x[i]) <= 'Z')) {
                found = false;
            } else {
                i++;
            }
        } else {
            i = 9;
        }
    }
    return found;
}

void CreateEmptyArray () {
    int i;
    for (i = 0; i < 9; i++) {
        CreateEmpty(&x[i]);
    }
}

void PDA (myKata kata) {
    myKata kata1;
    int line;
    boolean cek = true;
    boolean tmp;

    line = 0;
    CreateEmptyArray();
    Push(&x[0],'S');
    openFile(kata);
    do {
        readLine();
        line++;
        while ((!EOL) && (cek)) {
            FixArray();
            createEmpty(&kata1);
            kata1 = getKata();
            toLower(&kata1);
            kata1.line = line;
            tmp = EOL;
            printf("%d\t%s\n",kata1.line,kata1.kata);
            tes(kata1,&cek);
            EOL = tmp;
        }
   } while ((!EOf) && (cek));
   
   if (!cek || !isEmptyArray()) {
       printf("COMPILE FAILED AT %d\n",line);
   } else {
       printf("COMPILE SUCCESSFUL\n");
   }
   closeFile();
}

static int lineTemp = 0;

void tes (myKata kata,boolean * cek) {
   int i;
   int z;
   int y;
   char a;
   char prev;
   myKata temp;
   myKata dum;
   createEmpty(&dum);
   boolean found = true;
   temp.kata = kata.kata;
   temp.length = kata.length;
   temp.line = kata.line;

    while (IsNonTerminal()) {
        if (IsInArray('S')) {
            doS();
        } else if (IsInArray('Q')) {
            doQ();
        } else if (IsInArray('C')) {
            doC();
        } else if (IsInArray('A')) {
            doA();
        } else if (IsInArray('K')) {
            doK();
        } else if (IsInArray('O')) {
            i = FindTop('O');
            doO(&temp,cek);
        } else if (IsInArray('B')) {
            doB();
        }
    }
   found = true;
   while (IsTerminal() && found) {
        if (IsInArray('b')) {
            if (isSameBegin(temp)) {
                if (lineTemp != temp.line) {
                    dob();
                    lineTemp = temp.line;
                } else {
                    (*cek) = false;
                }
                found = false;
            } else if (isNull(temp)) {
                found = false;
            } else {
                i = FindTop('b');
                DeleteStack(&x[i]);
            }
        } else if (IsInArray('e')) {
            if (isSameEnd(temp)) {
                if (lineTemp != temp.line) {
                    doe();
                    lineTemp = temp.line;
                } else {
                    (*cek) = false;
                }
                found = false;
            } else if (isNull(temp)) {
                found = false;
            } else {
                i = FindTop('e');
                DeleteStack(&x[i]);
            }
        } else if (IsInArray('w')) {
            if (isSameWhile(temp)) {
                if (lineTemp != temp.line) {
                    dow();
                    lineTemp = temp.line;
                } else {
                    (*cek) = false;
                }
                found = false;
            } else if (isNull(temp)) {
                found = false;
            } else {
                i = FindTop('w');
                DeleteStack(&x[i]);
            }
        } else if (IsInArray('d')) {
            if (isSameDo(temp)) {
                if (temp.line == lineTemp) {
                    dod();
                    
                } else {
                    (*cek) = false;
                }
                found = false;
            } else if (isNull(temp)) {
                found = false;
            } else {
                i = FindTop('d');
                DeleteStack(&x[i]);
            }
        } else if(IsInArray('r')) {
            if (isSameRepeat(temp)) {
                if (lineTemp != temp.line) {
                    dor();
                    lineTemp = temp.line;
                } else {
                    (*cek) = false;
                }
                found = false;
            } else if (isNull(temp)) {
                found = false;
            } else {
                i = FindTop('r');
                DeleteStack(&x[i]);
            }
        }else if(IsInArray('u')) {
            if (isSameUntil(temp)) {
                if (lineTemp != temp.line) {
                    dou();
                    lineTemp = temp.line;
                } else {
                    (*cek) = false;
                }
                found = false;
            } else if (isNull(temp)) {
                found = false;
            } else {
                i = FindTop('u');
                DeleteStack(&x[i]);
            }
        }else if(IsInArray('i')) {
            if (isSameIf(temp)) {
                if (lineTemp != temp.line) {
                    doi();
                    lineTemp = temp.line;
                } else {
                    (*cek) = false;
                }
                found = false;
            } else if (isNull(temp)) {
                found = false;
            } else {
                i = FindTop('i');
                DeleteStack(&x[i]);
            }
        }else if(IsInArray('t')) {
            if (isSameThen(temp)) {
                if (lineTemp == temp.line) {
                    dot();
                } else {
                    (*cek) = false;
                }
                found = false;
            } else if (isNull(temp)) {
                found = false;
            } else {
                i = FindTop('t');
                DeleteStack(&x[i]);
            }
        }else if(IsInArray('n')) {
            if (isSameElse(temp)) {
                if (lineTemp != temp.line) {
                    don();
                    lineTemp = temp.line;
                } else {
                    (*cek) = false;
                }
                found = false;
            } else if (isNull(temp)) {
                found = false;
            } else {
                i = FindTop('n');
                DeleteStack(&x[i]);
            }
        }else if (IsInArray('m')) {
            if (isSameInput(temp)) {
                if (lineTemp != temp.line) {
                    dom();
                    lineTemp = temp.line;
                } else {
                    (*cek) = false;
                }
                found = false;
            } else if (isNull(temp)) {
                found = false;
            } else {
                i = FindTop('m');
                DeleteStack(&x[i]);
            }
        } else if (IsInArray('o')) {
            if (isSameOutput(temp)) {
                if (lineTemp != temp.line) {
                    doo();
                    lineTemp = temp.line;
                } else {
                    (*cek) = false;
                }
                found = false;
            } else if (isNull(temp)) {
                found = false;
            } else {
                i = FindTop('o');
                DeleteStack(&x[i]);
            }
        } else if (IsInArray('(')) {
            i = FindTop('(');
            if (lineTemp == temp.line) {
                if (temp.kata[0] == '(') {
                    if (isSameCondition(temp)) {
                        doBuCond(&temp,cek);
                        found = false;
                    } else if (isSameOperasi(temp)) {
                        doBuOp(&temp,cek,i);
                        found = false;
                    } else if (IsVariabel(temp)) {
                        doBuVar(&temp,cek,i);
                        found = false;
                    } else {
                        i = FindTop('(');
                        DeleteStack(&x[i]);
                    }
                } else {
                    i = FindTop('(');
                    DeleteStack(&x[i]);
                }
            } else {
                (*cek) = false;
                found = false;
            }
        } else if (IsInArray('y')) {
            i = FindTop('y');
                if (IsOperasi(temp)) {
                    doy(&temp,cek);
                    dosd(&temp,cek);
                    y = 0;
                    prev = '\0';
                    for (z = 0; z < temp.length; z++) {
                        if (temp.kata[z] != '(' && temp.kata[z] != ')') {
                            dum.kata[y] = temp.kata[z];
                            if (prev == ')') {
                                if ((temp.kata[z] != '+') && (temp.kata[z] != '-') && (temp.kata[z] != '*') && (temp.kata[z] != '/')) {
                                //(*cek) = false;
                                }
                            }
                            y++;
                            prev = temp.kata[z];
                        } else if (temp.kata[z] == '(') {
                            if ((prev != '+') && (prev != '-') && (prev != '*') && (prev != '/') && (prev != '\0')) {
                                (*cek) = false;
                            }
                        } else if (temp.kata[z] == ')') {
                            if (prev == '+' || prev == '-' || prev == '*' || prev == '/') {
                                (*cek) = false;
                            } else {
                                prev = temp.kata[z];
                            }
                        }  
                    }
                    temp.kata = dum.kata;
                    temp.length = y;
                    checkO(&temp,cek);
                    found = false;
                } else {
                    i = FindTop('y');
                    DeleteStack(&x[i]);
                }
        } else if (IsInArray('{')) {
            if (isSameBuKur(temp)) {
                i = FindTop('{');
                dobk();
                if (temp.kata[(temp.length)-1] == '}') {
                    dotk();
                } 
                found = false;
            } else if (isNull(temp)) {
                found = false;
            } else {
                i = FindTop('{');
                DeleteStack(&x[i]);
            }
        } else if (IsInArray('}')) {
            if (temp.kata[(temp.length)-1] == '}') {
                dotk();
                lineTemp = temp.line;
                found = false;
            } else if (isNull(temp)) {
                found = false;
            } else {
                found = false;
            }
        } else {
            (*cek) = false;
            found = false;
        }
   }
}